import prisma from '../lib/prisma';
import { 
  CreateAuditLogDto, 
  AuditLog, 
  AuditLogFilters, 
  AuditLogQueryResult 
} from '../types/audit';
import { ApiError } from '../utils/ApiError';
import { StatusCodes } from 'http-status-codes';

export class AuditLogService {
  constructor(private readonly prismaClient = prisma) {}

  async createAuditLog(data: CreateAuditLogDto): Promise<AuditLog> {
    try {
      const auditLog = await this.prismaClient.auditLog.create({
        data: {
          action: data.action,
          entityType: data.entityType,
          entityId: data.entityId,
          userId: data.userId,
          details: data.details || {},
          metadata: data.metadata || {}
        }
      });
      return auditLog as AuditLog;
    } catch (error: any) {
      throw new ApiError(
        StatusCodes.INTERNAL_SERVER_ERROR,
        'Error creating audit log'
      );
    }
  }

  async getAuditLog(id: string): Promise<AuditLog> {
    try {
      const auditLog = await this.prismaClient.auditLog.findUnique({
        where: { id }
      });

      if (!auditLog) {
        throw new ApiError(StatusCodes.NOT_FOUND, 'Audit log not found');
      }

      return auditLog as AuditLog;
    } catch (error) {
      if (error instanceof ApiError) throw error;
      throw new ApiError(
        StatusCodes.INTERNAL_SERVER_ERROR,
        'Error fetching audit log'
      );
    }
  }

  async getAuditLogs(filters: AuditLogFilters): Promise<AuditLogQueryResult> {
    const {
      page = 1,
      limit = 10,
      action,
      entityType,
      userId,
      startDate,
      endDate
    } = filters;

    try {
      const where = {
        ...(action && { action }),
        ...(entityType && { entityType }),
        ...(userId && { userId }),
        ...(startDate && endDate && {
          createdAt: {
            gte: startDate,
            lte: endDate
          }
        })
      };

      const [total, logs] = await Promise.all([
        this.prismaClient.auditLog.count({ where }),
        this.prismaClient.auditLog.findMany({
          where,
          skip: (page - 1) * limit,
          take: limit,
          orderBy: {
            createdAt: 'desc'
          }
        })
      ]);

      const totalPages = Math.ceil(total / limit);
      const hasMore = page < totalPages;

      return {
        logs: logs as AuditLog[],
        total,
        page,
        limit,
        hasMore
      };
    } catch (error) {
      throw new ApiError(
        StatusCodes.INTERNAL_SERVER_ERROR,
        'Error fetching audit logs'
      );
    }
  }

  async deleteAuditLog(id: string): Promise<void> {
    try {
      await this.prismaClient.auditLog.delete({
        where: { id }
      });
    } catch (error: any) {
      if (error?.code === 'P2025') {
        throw new ApiError(StatusCodes.NOT_FOUND, 'Audit log not found');
      }
      throw new ApiError(
        StatusCodes.INTERNAL_SERVER_ERROR,
        'Error deleting audit log'
      );
    }
  }

  async deleteOldAuditLogs(olderThan: Date): Promise<number> {
    try {
      const result = await this.prismaClient.auditLog.deleteMany({
        where: {
          createdAt: {
            lt: olderThan
          }
        }
      });
      return result.count;
    } catch (error) {
      throw new ApiError(
        StatusCodes.INTERNAL_SERVER_ERROR,
        'Error deleting old audit logs'
      );
    }
  }
}
